
//--------------------------------------------------------------------------------------------------------------------
// Add the specified calendar object to the popup window in preparation to displaying it.
function AddCalendarToPopupWindow(calendar)
{
	this.contents = calendar;
	this.populated = false;
}

//--------------------------------------------------------------------------------------------------------------------
// Allow selection of a date from the calendar and display the selection in the specified target element. The calendar
// is displayed at a location specified by anchor. The display target is assumed to be a div element. The hiddenField
// is used to pass the selection back to the server side during postback.
function AllowSelection(displayTarget, hiddenField, anchor, useDropDonwListNavigation, beginYear, endYear)
{
	try
	{
		this.useDropDonwListNavigation = useDropDonwListNavigation;
		this.beginYear = beginYear;
		this.endYear = endYear;
		
		window.displayTarget = window.document.getElementById(displayTarget);
		window.hiddenField = window.document.getElementById(hiddenField);
		window.calendarInstance = this;

		var dateExpression = new RegExp("[0-9]{1,2}/[0-9]{1,2}/[0-9]{4}");
		var displayTargetText = new String(window.displayTarget.value);
		if ((displayTargetText.match(dateExpression) == null) && (window.hiddenField.value.match(dateExpression) != null))
		{
			displayTargetText = new String(window.hiddenField.value);
			window.displayTarget.value = displayTargetText;
		}
			
		if (displayTargetText.match(dateExpression) == null)
			this.currentDate = new Date();
		else
			this.currentDate = new Date(GetTimeFromDateString(displayTargetText));
		this.ShowCalendar(anchor);
	}
	catch (e)
	{
		alert('AllowSelection: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Attach an event handler to manage mouse-up messages.
function AttachMouseEventHandler()
{
	try
	{
		window.popupWindowOldEventListener = window.document.onmouseup;
		if (window.popupWindowOldEventListener != null)
			window.document.onmouseup = new Function("window.popupWindowOldEventListener(); HideAllPopupWindows();");
		else
			window.document.onmouseup = HideAllPopupWindows;
	}
	catch (e)
	{
		alert('AttachMouseEventHandler: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Constructor for the calendar.
function Calendar()
{
	try
	{
		var c = (arguments.length == 1) ? new PopupWindow(arguments[0]) : new PopupWindow();

		c.monthNames = new Array('Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
		c.dayHeaders = new Array("S", "M", "T", "W", "T", "F", "S");
		c.showSelectedDate = "ShowSelectedDate";
		c.resetCalendar = "ResetCalendar";
		c.weekStartDay = 0;
		c.currentDate = null;
		c.todayText = "Today";
		c.resetText = "Reset";
		c.useDropDonwListNavigation = false;
		window.calendarInstance = null;
		window.displayTarget = null;
		c.ShowCalendar = ShowCalendar;
		c.GetCalendar = GetCalendar;
		c.AllowSelection = AllowSelection;

		return c;
	}
	catch (e)
	{
		alert('Calendar: ' + e);
	}
	return null;
}

//--------------------------------------------------------------------------------------------------------------------
// Return a string which conatins the specified value with a leading 0 if the value is less than 10.
function EnsureTwoDigits(value)
{
	return ((value < 10) ? "0" : "") + value;
}

//--------------------------------------------------------------------------------------------------------------------
// Return a string representation of the date object formatted to "mm/dd/yyyy".
function FormatDate(date)
{
	var m = EnsureTwoDigits(date.getMonth() + 1);
	var d = EnsureTwoDigits(date.getDate());
	return m + "/" + d + "/" + date.getFullYear();
}

//--------------------------------------------------------------------------------------------------------------------
// Compute the position for the calendar relative to specified anchor but in terms of screen coordinates.
function GetAbsoluteAnchorPosition(anchor)
{
	var position = GetRelativeAnchorPosition(anchor);
	if (isNaN(window.screenX))
	{
		position.x = window.screenLeft + (position.x - window.document.body.scrollLeft);
		position.y = window.screenTop + (position.y - window.document.body.scrollTop);
	}
	else
	{
		position.x += (window.screenX + (window.outerWidth - window.innerWidth) - window.pageXOffset);
		position.y += (window.screenY + (window.outerHeight - 24 - window.innerHeight) - window.pageYOffset);
	}

	return position;
}

//--------------------------------------------------------------------------------------------------------------------
// Return an HTML formatted string for the calendar display.
function GetCalendar()
{
	try
	{
		var now = new Date();
		var isWindowed = (this.calendarSite == null);
		
		var result = (isWindowed ?
			'<html><head><title>Select Date</title>' + GetCalendarStyles() +
			'</head><body marginwidth="0" marginheight="0" topmargin="0" rightmargin="0" leftmargin="0"><center><table width="100%">' :
			'<table class="CalendarBorder">');

		var month = (arguments.length > 0) ? arguments[0] : (this.currentDate.getMonth() + 1);
		var year = (arguments.length > 1) ? arguments[1] : this.currentDate.getFullYear();
		
		var daysInMonth = new Array(0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31);
		if ((((year % 4) == 0) && ((year % 100) != 0)) || ((year % 400) == 0))
			daysInMonth[2] = 29;

		var currentMonth = new Date(year, month - 1, 1);
		var displayYear = year;
		var displayMonth = month;

		var displayDate = 1;
		var weekday =  currentMonth.getDay();
		var offset = (weekday >= this.weekStartDay) ? (weekday - this.weekStartDay) : (7 - this.weekStartDay + weekday);
		if (offset > 0)
		{
			displayMonth--;
			if (displayMonth < 1)
			{
				displayMonth = 12;
				displayYear--;
			}
			displayDate = daysInMonth[displayMonth] - offset + 1;
		}

		var nextMonth = month + 1;
		var nextMonthYear = year;
		if (nextMonth > 12)
		{
			nextMonth = 1;
			nextMonthYear++;
		}
		
		var lastMonth = month - 1;
		var lastMonthYear = year;
		if (lastMonth < 1)
		{
			lastMonth = 12;
			lastMonthYear--;
		}
		
		result += isWindowed ? '<tr>' : '<table width="100%"><tr>';

		var windowReference = isWindowed ? "window.opener." : "";
		var refresh = windowReference + "RefreshCalendar";
		var refreshLink = 'javascript:' + refresh;
		
		if (this.useDropDonwListNavigation)
		{
			result += '<td class="CalendarMonthNavigation">' +
				'<select class="CalendarMonthNavigation" name="monthList" onChange="' + refresh + '(' + this.index +
				',this.options[this.selectedIndex].value - 0,' + year + ');">';
				
			for (var monthCounter = 1; monthCounter <= 12; monthCounter++)
			{
				var selected = (monthCounter == month) ? 'selected' : '';
				result += '<option value="' + monthCounter + '" ' + selected + '>' + this.monthNames[monthCounter - 1] + '</option>';
			}
			result += '</select></td><td class="CalendarMonthNavigation">&nbsp;</td>';

			result += '<td class="CalendarYearNavigation">' +
				'<select class="CalendarYearNavigation" name="yearList" onChange="' + refresh + '(' + this.index +
				',' + month + ', this.options[this.selectedIndex].value - 0);">';
			
			for (var y = this.beginYear, end = this.endYear; y <= end; y++)
			{
				var selected = (y == year) ? 'selected' : '';
				result += '<option value="' + y + '" '+ selected + '>' + y + '</option>';
			}
			result += '</select></td>';
		}
		else
		{
			result +=
				'<td class="CalendarMonthNavigation"><a class="CalendarMonthNavigation" href="' + refreshLink +
				'(' + this.index + ',' + lastMonth + ',' + lastMonthYear + ');">&lt;&lt;</a></td>\n' +
				'<td class="CalendarMonthNavigation"><span class="CalendarMonthNavigation">' + this.monthNames[month - 1] +
				' ' + year + '</span></td>\n' +
				'<td class="CalendarMonthNavigation"><a class="CalendarMonthNavigation" href="' + refreshLink + '(' +
				this.index + ',' + nextMonth + ',' + nextMonthYear + ');">&gt;&gt;</a></td>\n';
		}

		result += '</tr></table><table align="center"><tr>';
			
		for (var j = 0; j < 7; j++)
			result += '<td class="CalendarDayColumnHeader" width="20">' +
				'<span class="CalendarDayColumnHeader">' + this.dayHeaders[(this.weekStartDay + j) % 7] + '</td>';
		result += '</tr>';
		
		for (var row = 1; row < 7; row++)
		{
			result += '<tr>';
			for (var col = 1; col < 8; col++)
			{
				var dateClass = "";
				if ((displayMonth == (this.currentDate.getMonth() + 1)) && (displayDate == (this.currentDate.getDate()))
					&& ((displayYear == this.currentDate.getFullYear())))
					dateClass = "CalendarCurrentDate";
				else if (displayMonth == month)
					dateClass = "CalendarCurrentMonthDate";
				else
					dateClass = "CalendarOtherMonthDate";

				result += '<td class="' + dateClass + '"><a href="javascript:' + windowReference + this.showSelectedDate + '(' +
					displayYear + ',' + displayMonth + ',' + displayDate + ');' + windowReference + 'HideCalendar(' + this.index +
					');" class="' + dateClass + '">' + displayDate + '</a></td>';

				displayDate++;
				if (displayDate > daysInMonth[displayMonth])
				{
					displayDate = 1;
					displayMonth++;
				}
				if (displayMonth > 12)
				{
					displayMonth = 1;
					displayYear++;
				}
			}
			result += '</tr>';
		}

		result += '<tr><td colspan="3" align="center" class="CalendarTodayText">' +
			'<a class="CalendarTodayText" href="javascript:' + windowReference + this.showSelectedDate +
			'(\'' + now.getFullYear() + '\',\'' +  (now.getMonth() + 1) + '\',\'' + now.getDate() + '\');' +
			windowReference + 'HideCalendar(' + this.index + ');">' + this.todayText + '</a></td>';

		result += '<td class="CalendarTodayText">&nbsp;</td><td colspan="3" align="center" class="CalendarTodayText">' +
			'<a class="CalendarTodayText" href="javascript:' + windowReference + this.resetCalendar + '(' +
			this.index + ');' + windowReference + 'HideCalendar(' + this.index + ');">' + this.resetText +
			'</a></td></tr></table></td></tr></table>';

		if (isWindowed)
			result += "</center></body></html>";

		return result;
	}
	catch (e)
	{
		alert('GetCalendar : ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Write the style for the calendar to the window.
function GetCalendarStyles()
{
	var styles =
		"<style>\n" +
		".CalendarYearNavigation,\n" +
		".CalendarMonthNavigation\n" +
		"{\n" +
		"	text-align:center;\n" +
		"	vertical-align:center;\n" +
		"	text-decoration:none;\n" +
		"	color:#000000;\n" +
		"	font-weight:bold;\n" +
		"}\n" +
		".CalendarDayColumnHeader,\n" +
		".CalendarYearNavigation,\n" +
		".CalendarMonthNavigation,\n" +
		".CalendarCurrentMonthDate,\n" +
		".CalendarOtherMonthDate,\n" +
		".CalendarCurrentDate,\n" +
		".CalendarTodayText\n" +
		"{\n" +
		"	font-family:Verdana, Arial, Helvetica, sans-serif;\n" +
		"	font-size:10px;\n" +
		"}\n" +
		"td.CalendarDayColumnHeader\n" +
		"{\n" +
		"	text-align:center;\n" +
		"	font-weight:bold;\n" +
		"	border-collapse: collapse;\n" +
		"	border:thin solid #C0C0C0;\n" +
		"	border-width:1px 0px 1px 0px;\n" +
		"}\n" +
		".CalendarCurrentMonthDate,\n" +
		".CalendarOtherMonthDate,\n" +
		".CalendarCurrentDate\n" +
		"{\n" +
		"	text-align:center;\n" +
		"	text-decoration:none;\n" +
		"}\n" +
		".CalendarCurrentMonthDate,\n" +
		".CalendarCurrentDate\n" +
		"{\n" +
		"	color:#000000;\n" + 
		"}\n" +
		".CalendarOtherMonthDate\n" +
		"{\n" +
		"	color:#808080;\n" +
		"}\n" +
		"td.CalendarCurrentDate\n" + 
		"{\n" + 
		"	text-align:center;\n" +
		"	border:thin solid black;\n" + 
		"}\n" +
		"td.CalendarTodayText\n" +
		"{\n" +
		"	border:thin solid #C0C0C0;\n" +
		"	border-width:1px 0px 0px 0px;\n" +
		"}\n" +
		"a.CalendarTodayText\n" +
		"{\n" +
		"	color:black;\n" +
		"}\n" +
		".CalendarBorder\n" +
		"{\n" +
		"	border:thin solid #808080;\n" +
		"}\n" +
		"</style>\n";
		
	return styles;
}

//--------------------------------------------------------------------------------------------------------------------
// Compute the position for the calendar relative to specified anchor but in terms of window coordinates.
function GetRelativeAnchorPosition(anchor)
{
	var o = window.document.getElementById(anchor);
	
	var x = o.offsetLeft;
	for (var i = o.offsetParent; i != null; i = i.offsetParent)
		x += i.offsetLeft;

	var y = o.offsetTop;
	for (var i = o.offsetParent; i != null; i = i.offsetParent)
		y += i.offsetTop;
		
	var position = new Object();
	position.x = x;
	position.y = y;
	return position;
}

//--------------------------------------------------------------------------------------------------------------------
// Return the time (in number of milliseconds since midnight 1/1/1970 from the specified date string.
function GetTimeFromDateString(dateString)
{
	var pattern = /[^/]+/g;
	var result;
	var dateComponents = new Array();
	while ((result = pattern.exec(dateString)) != null)
		dateComponents.push(result[0]);
	
	var newdate = new Date(dateComponents[2], dateComponents[0] - 1, dateComponents[1]);
	return newdate.getTime();
}

//--------------------------------------------------------------------------------------------------------------------
// Hide all calendar popup windows.
function HideAllPopupWindows(e)
{
	try
	{
		for (var i = 0; i < popupWindowObjects.length; i++)
			if (popupWindowObjects[i] !=  null)
				popupWindowObjects[i].HideIfNotClicked(e);
	}
	catch (e)
	{
		alert('HideAllPopupWindows: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Hide the calendar at the specified index.
function HideCalendar(index)
{
	try
	{
		window.popupWindowObjects[index].HidePopup();
	}
	catch (e)
	{
		alert('HideCalendar: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Hide the calendar popup window.
function HidePopupWindow()
{
	try
	{
		if (this.calendarSite == null)
		{
			if (this.popupWindow && !this.popupWindow.closed)
			{
				this.popupWindow.close();
				this.popupWindow = null;
			}
		}
		else
			window.document.getElementById(this.calendarSite).style.visibility = "hidden";
	}
	catch (e)
	{
		alert('HidePopupWindow: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Hide the calendar poup window if a mouse click occurred outside the calendar site.
function HidePopupWindowIfNotClickedUpon(e)
{
	try
	{
		if (!this.IsClicked(e))
			this.HidePopup();
	}
	catch (e)
	{
		alert('HidePopupWindowIfNotClickedUpon: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Determine if a mouse click occurred within the calendar site.
function IsPopupWindowClickedUpon(e)
{
	try
	{
		if (window.document.all)	// IE
		{
			for (var t = window.event.srcElement; t.parentElement != null; t = t.parentElement)
				if (t.id == this.calendarSite)
					return true;
		}
		else if (e && e.orginalTarget)
		{
			for (var t = e.originalTarget; t.parentNode != null; t = t.parentNode)
				if (t.id == this.calendarSite)
					return true;
		}
	}
	catch (e)
	{
		alert('IsPopupWindowClickedUpon: ' + e);
	}

	return false;
}

//--------------------------------------------------------------------------------------------------------------------
function LogMessage(message)
{
	var messageElement = window.document.getElementById("message");
	if (messageElement != null)
		messageElement.innerHTML += (message + "<br>");
}

//--------------------------------------------------------------------------------------------------------------------
// Constructor for the calendar popup window. 
function PopupWindow()
{
	try
	{
		if (!window.popupWindowIndex)
			window.popupWindowIndex = 0;
			
		if (!window.popupWindowObjects)
			window.popupWindowObjects = new Array();

		if (!window.listenerAttached)
		{
			AttachMouseEventHandler();
			window.listenerAttached = true;
		}
		
		this.index = popupWindowIndex++;
		popupWindowObjects[this.index] = this;

		this.calendarSite = (arguments.length == 1) ? arguments[0] : null;
		this.popupWindow = null;
		this.populated = false;
		this.visible = false;
		this.contents = "";

		this.AddCalendar = AddCalendarToPopupWindow;
		this.Refresh = RefreshPopupWindow;
		this.ShowPopup = ShowPopupWindow;
		this.HidePopup = HidePopupWindow;
		this.IsClicked = IsPopupWindowClickedUpon;
		this.HideIfNotClicked = HidePopupWindowIfNotClickedUpon;
	}
	catch (e)
	{
		alert('PopupWindow: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Refresh the contents of the calendar at the specified index.
function RefreshCalendar(index)
{
	try
	{
		var calendar = window.popupWindowObjects[index];
		if (arguments.length > 1)
			calendar.AddCalendar(calendar.GetCalendar(arguments[1], arguments[2], arguments[3]));
		else
			calendar.AddCalendar(calendar.GetCalendar());
		calendar.Refresh();
	}
	catch (e)
	{
		alert('RefreshCalendar: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Refresh the calendar site with the contents of the calendar.
function RefreshPopupWindow()
{
	try
	{
		if (this.calendarSite == null)
		{
			var w = this.popupWindow;
			if ((w != null) && (!w.closed))
			{
				var d = w.document;
				d.open();
				d.writeln(this.contents);
				d.close();
				w.focus();
			}
		}
		else
			window.document.getElementById(this.calendarSite).innerHTML = this.contents;
	}
	catch (e)
	{
		alert('RefreshPopupWindow: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Initialize and display the calendar.
function ShowCalendar(anchor)
{
	try
	{
		this.AddCalendar(this.GetCalendar());
		this.ShowPopup(anchor);
	}
	catch (e)
	{
		alert('ShowCalendar: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Show the calendar popup window and position it just below the anchor.
function ShowPopupWindow(anchor)
{
	try
	{
		var position = (this.calendarSite == null) ? GetAbsoluteAnchorPosition(anchor) : GetRelativeAnchorPosition(anchor);
		
		if (!this.populated && (this.contents != ""))
		{
			this.populated = true;
			this.Refresh();
		}

		if (this.calendarSite == null)
		{
			if ((this.popupWindow == null) || (this.popupWindow.closed))
			{
				var features = "toolbar=no,location=no,status=no,menubar=no,scrollbars=auto,resizable,alwaysRaised,dependent,titlebar=no";
				var sizeSpec = "width=150,height=165";
				var positionSpec = "left=" + position.x + ",top=" + position.y;
				this.popupWindow = window.open("", "", features + "," + sizeSpec + "," + positionSpec);
			}
			this.Refresh();
		}
		else
		{
			var calendarSite = window.document.getElementById(this.calendarSite);
			calendarSite.style.left = position.x + "px";
			calendarSite.style.top = position.y + "px";
			calendarSite.style.visibility = "visible";
		}
	}
	catch (e)
	{
		alert('ShowPopupWindow: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Show the current date selection within the element identified as the receipient of that information.
function ShowSelectedDate(y, m, d)
{ 
	try
	{
		var selection = FormatDate(new Date(y, m - 1, d));
		if (window.displayTarget != null)
			window.displayTarget.value = selection;
		
		if (window.hiddenField != null)
			window.hiddenField.value = selection;
	}
	catch (e)
	{
		alert('ShowSelectedDate: ' + e);
	}
}

//--------------------------------------------------------------------------------------------------------------------
// Reset the selection and set the hidden field to empty string.
function ResetCalendar(index)
{
	try
	{
		if (window.displayTarget != null)
			window.displayTarget.value = window.popupWindowObjects[index].promptText;
		if (window.hiddenField != null)
			window.hiddenField.value = '';
		HideCalendar(index);
	}
	catch (e)
	{
		alert('ResetCalendar: ' + e);
	}
}


// --- EOF ---
